/*for ndisc*/
#include <linux/in6.h>
#include <linux/if_packet.h> //for PACKET_HOST
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/if_inet6.h>
#include <net/addrconf.h>
#include <net/route.h>
#include <linux/inet.h>
#include <net/ipv6.h>
/*for arp*/
#include <linux/inetdevice.h>
#include <linux/version.h>
#include <net/arp.h>
#include <net/ax25.h>
/* for h3c switch bug, added by mayc 2016/04/22 */
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/inet.h>
#include <linux/socket.h>
#include <net/sock.h>
#include "socs/comm/socs.h"
#include "socs/mod/addr_opt.h"
#include "socs/mod/neigh.h"
#include "socs/mod/sap.h"

/***************************************NDISC FOR IPV6********************************************************/
static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data)
{
	int pad   = ndisc_addr_option_pad(skb->dev->type);
	int data_len = skb->dev->addr_len;
	int space = ndisc_opt_addr_space(skb->dev);
	u8 *opt = skb_put(skb, space);
	opt[0] = type;
	opt[1] = space >> 3;
	memset(opt + 2, 0, pad);
	opt   += pad;
	space -= pad;
	memcpy(opt + 2, data, data_len);
	data_len += 2;
	opt += data_len;

	if ((space -= data_len) > 0) {
		memset(opt, 0, space);
	}
}
static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
									   int len)
{
	int hlen = LL_RESERVED_SPACE(dev);
	int tlen = dev->needed_tailroom;
	struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
	struct sk_buff *skb;
	int err;
	skb = sock_alloc_send_skb(sk,
							  hlen + sizeof(struct ipv6hdr) + len + tlen,
							  1, &err);

	if (!skb) {
		log_err(ERR_ALLOC_FAILED, "ndisc: %s failed to allocate an skb, err=%d",
				__func__, err);
		return NULL;
	}

	skb->protocol = htons(ETH_P_IPV6);
	skb->dev = dev;
	skb_reserve(skb, hlen + sizeof(struct ipv6hdr));
	skb_reset_transport_header(skb);
	return skb;
}
static void ip6_nd_hdr(struct sk_buff *skb,
					   const struct in6_addr *saddr,
					   const struct in6_addr *daddr,
					   int hop_limit, int len)
{
	struct ipv6hdr *hdr;
	skb_push(skb, sizeof(*hdr));
	skb_reset_network_header(skb);
	hdr = ipv6_hdr(skb);
	ip6_flow_hdr(hdr, 0, 0);
	hdr->payload_len = htons(len);
	hdr->nexthdr = IPPROTO_ICMPV6;
	hdr->hop_limit = hop_limit;
	hdr->saddr = *saddr;
	hdr->daddr = *daddr;
}
static void ndisc_send_skb(struct sk_buff *skb,
						   const struct in6_addr *daddr,
						   const struct in6_addr *saddr)
{
	struct dst_entry *dst = skb_dst(skb);
	struct net *net = dev_net(skb->dev);
	struct sock *sk = net->ipv6.ndisc_sk;
	struct inet6_dev *idev;
	int err;
	struct icmp6hdr *icmp6h = icmp6_hdr(skb);
	u8 type;
	log_debug("socs ndisc_send_skb %pI6c  daddr %pI6c  ", saddr, daddr);
	type = icmp6h->icmp6_type;

	if (!dst) {
		struct sock *sk = net->ipv6.ndisc_sk;
		struct flowi6 fl6;
		icmpv6_flow_init(sk, &fl6, type, saddr, daddr, skb->dev->ifindex);
		dst = icmp6_dst_alloc(skb->dev, &fl6);

		if (IS_ERR(dst)) {
			kfree_skb(skb);
			return ;
		}

		skb_dst_set(skb, dst);
	}

	icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len,
										  IPPROTO_ICMPV6,
										  csum_partial(icmp6h,
												  skb->len, 0));
	ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);
	rcu_read_lock();
	idev = __in6_dev_get(dst->dev);
	IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
//	err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
//		      dst_output);
	err = dst_output(skb);

	if (!err) {
		ICMP6MSGOUT_INC_STATS(net, idev, type);
		ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
	}
	else
	{
		log_info("%s dst_output(skb) fail, return %d",__func__, err);
		//kfree_skb(skb);//mem :dst_output(skb); failed ,release by manual
		//0630 remove first, it seems make error
	}

	rcu_read_unlock();
}
static int pndisc_is_router(const void *pkey,
							struct net_device *dev)
{
	struct pneigh_entry *n;
	int ret = -1;
	read_lock_bh(&nd_tbl.lock);
	n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);

	if (n) {
		ret = !!(n->flags & NTF_ROUTER);
	}

	read_unlock_bh(&nd_tbl.lock);
	return ret;
}

/*! @function
********************************************************************************
<PRE>
Name 		: sap_kernel_udp_sendto
Function 	: wrapper of kernel_sendmsg
Parameters 	:
	sock 		struct socket *		kernel socket pointer
	buf 			void *				pointer to the send buffer
	len 			size_t				length of the buffer
	flags      	unsigned 				kernel_sendmsg flags
	addr 		struct sockaddr *		pointer to target 'sockaddr'
	addr_len 	int 					length of the 'addr' struct
Return value 	:
	>=0			length of bytes sent, success implied
	<0			error
Exception 	: none
--------------------------------------------------------------------------------
Remarks		: none
typical usage	:
--------------------------------------------------------------------------------
Author     	: <mayc@reyzar.com>
CreationTime 	: 2016/04/22
</PRE>
*******************************************************************************/
static int sap_kernel_udp_sendto(struct socket *sock, void *buff, size_t len,
								 unsigned flags, struct sockaddr *addr, int addr_len)
{
	struct kvec vec;
	struct msghdr msg;
	vec.iov_base = buff;
	vec.iov_len = len;
	memset(&msg, 0x00, sizeof(msg));
	msg.msg_name = addr;
	msg.msg_namelen = addr_len;
	msg.msg_flags = flags | MSG_DONTWAIT;
	return kernel_sendmsg(sock, &msg, &vec, 1, len);
}


/*! @function
********************************************************************************
<PRE>
Name 		: sap_send_ipv6_to_h3c
Function 	: send a normal ipv6 packet forwarding to switch
Parameters 	:
	daddr 		const struct in6_addr *	src of h3c packet
	saddr 		const struct in6_addr *	dst of h3c packet
Return value 	:
	>=0			length of bytes sent, success implied
	<0			error
Exception 	: none
--------------------------------------------------------------------------------
Remarks		: Fix saIPv6 address bug when using some h3c switches
typical usage	: Called after the sending of unsolicated nd packet
--------------------------------------------------------------------------------
Author     	: <mayc@reyzar.com>
CreationTime 	: 2016/04/22
</PRE>
*******************************************************************************/
static void sap_send_ipv6_to_h3c(
	const struct in6_addr *daddr,
	const struct in6_addr *saddr)
{
	int ret;
	struct socket *sock;
	struct sockaddr_in6 addr;
	static char *buffer = "hello, socs!";
	ret = sock_create_kern(PF_INET6, SOCK_DGRAM, 0, &sock);
	if (ret) {
		log_err(ERR_ALLOC_FAILED, "%s failed to allocate an sock", __func__);
	}
	else {
		memset(&addr, 0x00, sizeof(addr));
		addr.sin6_family = AF_INET6;
		addr.sin6_port = htons(0);
		addr.sin6_addr = *saddr;
		kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
		memset(&addr, 0x00, sizeof(addr));
		addr.sin6_family = AF_INET6;
		addr.sin6_port = htons(1000);
		addr.sin6_addr = *daddr;
		ret = sap_kernel_udp_sendto(sock, buffer, strlen(buffer), 0,
								(struct sockaddr *)&addr, sizeof(addr));
		if (ret)
		{log_err(ERR_SOCKET, "%s failed to send udp", __func__);
			printk("******[%s], dst:%pI6c   src:%pI6c send fail!\n", __FUNCTION__, daddr,
				   saddr);
		}

		sock_release(sock);
		sock = NULL;
	}
}

static void sap_send_na(struct net_device *dev, struct neighbour *neigh,
						const struct in6_addr *daddr,
						const struct in6_addr *solicited_addr,
						bool router, bool solicited, bool override, bool inc_opt)
{
	struct sk_buff *skb;
	const struct in6_addr *src_addr;
	struct nd_msg *msg;
	int optlen = 0;
	/* for anycast or proxy, solicited_addr != src_addr */
	src_addr = solicited_addr;

	if (inc_opt) {
		optlen += ndisc_opt_addr_space(dev);
	}

	skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); //mem  dst_output(skb); (DONE): if fail ,free skb

	if (!skb) {
		return ;
	}

	msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
	*msg = (struct nd_msg) {
		.icmph = {
			.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
			.icmp6_router = router,
			.icmp6_solicited = solicited,
			.icmp6_override = override,
		},
		.target = *solicited_addr,
	};

	if (inc_opt)
		ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
							   dev->dev_addr);

	ndisc_send_skb(skb, daddr, src_addr);
}
static int sap_recv_ns(struct sk_buff *skb, struct in6_addr *saIP,
					   struct in6_addr *dIP)
{
	struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
	const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
	struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
	u8 *lladdr = NULL;
	u32 ndoptlen = skb->tail - (skb->transport_header +
								offsetof(struct nd_msg, opt));
	struct ndisc_options ndopts;
	struct net_device *dev = skb->dev;
	struct inet6_ifaddr *ifp;
	struct inet6_dev *idev = NULL;
	struct neighbour *neigh;
	int dad = ipv6_addr_any(saddr);
	bool inc;
	int is_router = -1;
	struct in6_addr localmultaddr;
	log_debug("%s saddr %pI6c  daddr %pI6c saip %pI6c ", __func__, saddr, daddr,
			  saIP);

	int ret_code = NF_DROP; //default return drop

	msg->target = *dIP;
	ifaddr_to_multaddr(&msg->target, &localmultaddr);
	*daddr = localmultaddr;

	if (skb->len < sizeof(struct nd_msg)) {
		log_info( "NS: packet too short");
		return NF_ACCEPT;
	}

	if (ipv6_addr_is_multicast(&msg->target)) {
		log_info( "NS: multicast target address ");
		return NF_ACCEPT;
	}

	/*
	 * RFC2461 7.1.1:
	 * DAD has to be destined for solicited node multicast address.
	 */
	if (dad && !ipv6_addr_is_solict_mult(daddr)) {
		log_info( "NS: bad DAD packet (wrong destination)");
		return NF_ACCEPT;
	}

	if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
		log_info( "NS: invalid ND options");
		return NF_ACCEPT;
	}

	if (ndopts.nd_opts_src_lladdr) {
		lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);

		if (!lladdr) {
			log_info("NS: invalid link-layer address length");
			return NF_ACCEPT;
		}

		/* RFC2461 7.1.1:
		 *	If the IP source address is the unspecified address,
		 *	there MUST NOT be source link-layer address option
		 *	in the message.
		 */
		if (dad) {
			log_info("NS: bad DAD packet (link-layer address option)");
			return NF_ACCEPT;
		}
	}

	inc = ipv6_addr_is_multicast(daddr);
	ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);

	if (ifp) {
		if (ifp->flags & (IFA_F_TENTATIVE | IFA_F_OPTIMISTIC)) {
			if (dad) {
				/*
				 * We are colliding with another node
				 * who is doing DAD
				 * so fail our DAD process
				 */
				addrconf_dad_failure(ifp);
				return NF_ACCEPT;
			} else {
				/*
				 * This is not a dad solicitation.
				 * If we are an optimistic node,
				 * we should respond./
				 * Otherwise, we should ignore it.
				 */
				if (!(ifp->flags & IFA_F_OPTIMISTIC)) {
					goto out;
				}
			}
		}

		idev = ifp->idev;
	} else {
		struct net *net = dev_net(dev);
		idev = in6_dev_get(dev);

		if (!idev) {
			/* XXX: count this drop? */
			return NF_ACCEPT;
		}

		if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
			(idev->cnf.forwarding &&
			 (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
			 (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
			if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
				skb->pkt_type != PACKET_HOST &&
				inc != 0 /*&&
			    idev->nd_parms->proxy_delay != 0*/) {
				/*
				 * for anycast or proxy,
				 * sender should delay its response
				 * by a random time between 0 and
				 * MAX_ANYCAST_DELAY_TIME seconds.
				 * (RFC2461) -- yoshfuji
				 */
				struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);

				if (n) {
					pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
				}

				goto out;
			}
		} else {
			goto out;
		}
	}

	log_debug("%s  %pI6c  daddr %pI6c  target %pI6c", __func__, saddr, daddr,
			  &msg->target);

	if (is_router < 0) {
		is_router = idev->cnf.forwarding;
	}

	if (dad) {
		sap_send_na(dev, NULL, &in6addr_linklocal_allnodes, saIP,
					!!is_router, false, (ifp != NULL), true);
		goto out;
	}

	if (inc) {
		NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
	} else {
		NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
	}

	/*
	 *	update / create cache entry
	 *	for the source address
	 */
	neigh = __neigh_lookup(&nd_tbl, saddr, dev,
						   !inc || lladdr || !dev->addr_len);

	if (neigh)
		neigh_update(neigh, lladdr, NUD_STALE,
					 NEIGH_UPDATE_F_WEAK_OVERRIDE |
					 NEIGH_UPDATE_F_OVERRIDE);

	if (neigh || !dev->header_ops) {
		log_debug("%s  %pI6c  daddr %pI6c  target %pI6c saip %pI6c", __func__, saddr,
				  daddr, &msg->target, saIP);
		sap_send_na(dev, neigh, saddr, saIP,
					!!is_router,
					true, (ifp != NULL && inc), inc);

		//if (neigh) {
		//	neigh_release(neigh);  //mem(TODO) move out to release
		//}
	}
	if (neigh) {
		neigh_release(neigh);
	}

out:

	if (ifp) {
		in6_ifa_put(ifp);
	} else {
		in6_dev_put(idev);
	}

	return ret_code;
}


// Actually the address of ipv6.google.com
// added by mayc@reyzar.com @ 2016/04/22
static struct in6_addr h3c_addr = { { { 0x24, 0x04, 0x68, 0x00, 0x40, 0x05, 0x08, 0, 0, 0, 0, 0, 0, 0, 0x20, 0x0e } } };
int sap_send_unsol_na(struct in6_addr *saIP, const char *devname)
{
	struct net_device *dev;
	struct inet6_dev *idev;
	dev = dev_get_by_name(&init_net, devname);

	if (!dev) {
		return -1;
	}

	idev = in6_dev_get(dev);

	if (!idev) {
		dev_put(dev);
		return -1;
	}

	sap_send_na(dev, NULL, &in6addr_linklocal_allnodes, saIP,
				!!idev->cnf.forwarding, false, true, true);
	// send a ipv6 packet forwarding to h3c switch to fix the h3c ipv6 neighbour bug
	// added by mayc@reyzar.com @ 2016/04/22
	in6_dev_put(idev);
	dev_put(dev);
	sap_send_ipv6_to_h3c(&h3c_addr, saIP);
	return 0;
}


int sap_send_gratuitous_arp(struct in_addr *saIP, char *devname)
{
	struct net_device *dev ;
	unsigned char *sha;
	dev = dev_get_by_name(&init_net, devname);

	if (!dev) {
		return -1;
	}

	//sha="\0\0\0\0\0\0";
	sha = "\xff\xff\xff\xff\xff\xff";
	arp_send(ARPOP_REQUEST, ETH_P_ARP, *(__be32 *)saIP, dev, *(__be32 *)saIP, sha,
			 dev->dev_addr, sha);
	arp_send(ARPOP_REQUEST, ETH_P_ARP, *(__be32 *)saIP, dev, *(__be32 *)saIP, sha,
			 dev->dev_addr, sha);
	arp_send(ARPOP_REQUEST, ETH_P_ARP, *(__be32 *)saIP, dev, *(__be32 *)saIP, sha,
			 dev->dev_addr, sha);
	log_debug("[sap_send_gratuitous_arp]arp_send");
	dev_put(dev);
	return 0;
}

unsigned int sap_ndisc_rcv(struct sk_buff *skb)
{
	struct in6_addr daddr;
//	struct in6_addr tmp;
	struct in6_addr saIP;
	struct in6_addr dIP;
	daddr = ipv6_hdr(skb)->daddr;

	if (ipv6_addr_is_multicast(&daddr)) {
		struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
		daddr = msg->target;
		log_debug("sap_ndisc_recv,target %pI6c", &daddr);
		log_debug("sap_ndisc_recv,saddr %pI6c,daddr %pI6c", &ipv6_hdr(skb)->saddr,
				  &daddr);

		if (is_sap6(&daddr, &saIP, &dIP)) {
			//	if(!memcmp(daddr,&tmp,sizeof(struct in6_addr))){
			//                log_debug("the daddr %pI6  is in the sap and is local",daddr);
			return sap_recv_ns(skb, &daddr, &dIP);
		}
	}

	return NF_ACCEPT;
}

/**************************************ARP FOR IPV4********************************************/
static int sap_arp_process(struct sk_buff *skb)
{
	struct net_device *dev = skb->dev;
	struct in_device *in_dev = __in_dev_get_rcu(dev);
	struct arphdr *arp;
	unsigned char *arp_ptr;
	unsigned char *sha;
	__be32 sip, tip;
	u16 dev_type = dev->type;

	/*for test**/
//	skb->dev = dev;

	if (in_dev == NULL) {
		goto out;
	}

	arp = arp_hdr(skb);

	switch (dev_type) {
	default:
		if (arp->ar_pro != htons(ETH_P_IP) ||
			htons(dev_type) != arp->ar_hrd) {
			goto out;
		}

		break;

	case ARPHRD_ETHER:
	case ARPHRD_FDDI:
	case ARPHRD_IEEE802:

		/*
		 * ETHERNET, and Fibre Channel (which are IEEE 802
		 * devices, according to RFC 2625) devices will accept ARP
		 * hardware types of either 1 (Ethernet) or 6 (IEEE 802.2).
		 * This is the case also of FDDI, where the RFC 1390 says that
		 * FDDI devices should accept ARP hardware of (1) Ethernet,
		 * however, to be more robust, we'll accept both 1 (Ethernet)
		 * or 6 (IEEE 802.2)
		 */
		if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
			 arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
			arp->ar_pro != htons(ETH_P_IP)) {
			goto out;
		}

		break;

	case ARPHRD_AX25:
		if (arp->ar_pro != htons(AX25_P_IP) ||
			arp->ar_hrd != htons(ARPHRD_AX25)) {
			goto out;
		}

		break;

	case ARPHRD_NETROM:
		if (arp->ar_pro != htons(AX25_P_IP) ||
			arp->ar_hrd != htons(ARPHRD_NETROM)) {
			goto out;
		}

		break;
	}

	/* Understand only these message types */

	if (arp->ar_op != htons(ARPOP_REPLY) &&
		arp->ar_op != htons(ARPOP_REQUEST)) {
		goto out;
	}

	/*
	 *	Extract fields
	 */
	arp_ptr = (unsigned char *)(arp + 1);
	sha	= arp_ptr;
	arp_ptr += dev->addr_len;
	memcpy(&sip, arp_ptr, 4);
	arp_ptr += 4;
	arp_ptr += dev->addr_len;
	memcpy(&tip, arp_ptr, 4);
	/*
	 *	Check for bad requests for 127.x.x.x and requests for multicast
	 *	addresses.  If this is one such, delete it.
	 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)

	if (ipv4_is_multicast(tip) || ipv4_is_loopback(tip))
#else
	if (ipv4_is_multicast(tip) ||
		(!IN_DEV_ROUTE_LOCALNET(in_dev) && ipv4_is_loopback(tip)))
#endif
		goto out;

	/*
	 *     Special case: We must set Frame Relay source Q.922 address
	 */
	if (dev_type == ARPHRD_DLCI) {
		sha = dev->broadcast;
	}

	/*
	 *  Process entry.  The idea here is we want to send a reply if it is a
	 *  request for us or if it is a request for someone else that we hold
	 *  a proxy for.  We want to add an entry to our cache if it is a reply
	 *  to us or if it is a request for our address.
	 *  (The assumption for this last is that if someone is requesting our
	 *  address, they are probably intending to talk to us, so it saves time
	 *  if we cache their address.  Their address is also probably not in
	 *  our cache, since ours is not in their cache.)
	 *
	 *  Putting this another way, we only care about replies if they are to
	 *  us, in which case we add them to the cache.  For requests, we care
	 *  about those for us and those for our proxies.  We reply to both,
	 *  and in the case of requests for us we add the requester to the arp
	 *  cache.
	 */
	/* Special case: IPv4 duplicate address detection packet (RFC2131) */
	/*TODO*/
	log_debug("sip:%pI4,tip:%pI4,sha:%02x:%02x:%02x:%02x:%02x:%02x,dha:%02x:%02x:%02x:%02x:%02x:%02x",
			  &sip, &tip, *sha, *(sha + 1), *(sha + 2), *(sha + 3), *(sha + 4), *(sha + 5),
			  *(dev->dev_addr), *(dev->dev_addr + 1), *(dev->dev_addr + 2),
			  *(dev->dev_addr + 3), *(dev->dev_addr + 4), *(dev->dev_addr + 5));

	if (arp->ar_op == htons(ARPOP_REQUEST)) {
		arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, dev->dev_addr, sha);
	}

	return NF_STOLEN;
out:
	consume_skb(skb);
	return NF_DROP;
}
unsigned int sap_arp_rcv(struct sk_buff *skb)
{
	struct in_addr daddr;
	struct in_addr dIP;
	struct net_device *dev;
	struct in_device *ind;
	struct in_ifaddr *ina;
	unsigned char *arp_ptr;
	char str_addr[32] = {};
	struct arphdr *arp = arp_hdr(skb);
	arp_ptr = (unsigned char *)(arp + 1);
	sprintf(str_addr, "%pI4", arp_ptr + 16);
	str_to_addr4(str_addr, &daddr);

	if (is_sap_arp(&daddr, &dIP)) {
		dev = skb->dev;
		ina = NULL;

		if (!netif_running(dev) || !dev->ethtool_ops->get_link(dev)) {
			log_info("[sap_arp_rcv]%s is not running, return NF_DROP", dev->name);
			return NF_DROP;
		}

		ind = in_dev_get(dev);

		if (ind) {
			log_debug("[sap_arp_rcv]dev->name:%s", dev->name);

			for (ina = ind->ifa_list; ina != NULL; ina = ina->ifa_next) {
				if (dev->ifindex == LOOPBACK_IFINDEX) {
					continue;
				}

				if (memcmp(&ina->ifa_address, &dIP, sizeof(struct in_addr)) == 0) {
					return sap_arp_process(skb);
				}
			}

			in_dev_put(ind);
		}

		//log_info("sap_arp_rcv return NF_DROP");
		return NF_DROP;
		//return sap_arp_process(skb);
	}

//    log_debug("the daddr %pI4  is not in the sap and is local\n",&daddr);
	return NF_ACCEPT ;
}
